/*
 * ThermistorParamsPanel.cpp
 *
 * Copyright 2012 Pieter Agten
 *
 * This file is part of tltgen.
 *
 * tltgen is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * tltgen is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with tltgen.  If not, see <http://www.gnu.org/licenses/>.
 */

/**
 * @file   ThermistorParamsPanel.cpp
 * @author Pieter Agten (pieter.agten@gmail.com)
 * @date   11 sep 2012
 */

#include <stdexcept>
#include <boost/shared_ptr.hpp>

#include "Thermistor.hpp"

#include "ThermistorParamsPanel.hpp"

using boost::shared_ptr;

namespace tltgen {

  BEGIN_EVENT_TABLE(ThermistorParamsPanel, wxPanel)
  END_EVENT_TABLE()

  ThermistorParamsPanel::ThermistorParamsPanel(wxWindow* parent, wxWindowID id, const shared_ptr<ThermistorTable>& thermistorTable, const shared_ptr<LeastSquaresSolver>& leastSquaresSolver, const shared_ptr<TemperatureScale>& temperatureScale, const wxSize& size, long style) :
  wxPanel(parent, id, wxDefaultPosition, size, style, _("ThermistorParamsPanel")),
    thermistorTable(thermistorTable),
    leastSquaresSolver(leastSquaresSolver),
    temperatureScale(temperatureScale)
  {
    if (! isValidThermistorTable(thermistorTable)) {
      throw std::invalid_argument("The given thermistor table is invalid.");
    }
    if (! isValidLeastSquaresSolver(leastSquaresSolver)) {
      throw std::invalid_argument("The given least squares solver is invalid.");
    }
    if (! isValidTemperatureScale(temperatureScale)) {
      throw std::invalid_argument("The given temperature scale is invalid.");
    }
  
    wxBoxSizer *vbox = new wxBoxSizer(wxVERTICAL);
    SetSizer(vbox);

    thermistorTable->connectTableChangedObserver(boost::bind(&ThermistorParamsPanel::onThermistorTableChanged, this, _1, _2));
  }

  ThermistorParamsPanel::~ThermistorParamsPanel()
  {
  }

  bool ThermistorParamsPanel::isValidThermistorTable(const shared_ptr<ThermistorTable>& thermistorTable)
  {
    return thermistorTable.get() != NULL;
  }

  bool ThermistorParamsPanel::isValidLeastSquaresSolver(const shared_ptr<LeastSquaresSolver>& leastSquaresSolver)
  {
    return leastSquaresSolver.get() != NULL;
  }

  bool ThermistorParamsPanel::isValidTemperatureScale(const shared_ptr<TemperatureScale>& temperatureScale)
  {
    return temperatureScale.get() != NULL;
  }

  shared_ptr<TemperatureScale> ThermistorParamsPanel::getTemperatureScale() const
  {
    return this->temperatureScale;
  }
  void ThermistorParamsPanel::setTemperatureScale(const shared_ptr<TemperatureScale>& temperatureScale)
  {
    if (! isValidTemperatureScale(temperatureScale)) {
      throw std::invalid_argument("The given temperature scale is invalid.");
    }
    this->temperatureScale = temperatureScale;    
    updateValues();
  }
  
  void ThermistorParamsPanel::addThermistorModel(const shared_ptr<ThermistorModel>& thermistorModel)
  {
    if (thermistorModel->getNbParameters() > 0) {
      addThermistorModelPanel(thermistorModel);
    }
  }

  shared_ptr<ThermistorTable> ThermistorParamsPanel::getThermistorTable() const
  {
    return this->thermistorTable;
  }

  shared_ptr<LeastSquaresSolver> ThermistorParamsPanel::getLeastSquaresSolver() const
  {
    return this->leastSquaresSolver;
  }

  void ThermistorParamsPanel::updateValues()
  {
    for (boost::unordered_map<shared_ptr<ThermistorModel>, std::vector<wxTextCtrl*> >::const_iterator it = this->thermistorModelMap.begin(); it != this->thermistorModelMap.end(); ++it) {
      updateValues(it->first, it->second);
    }
  }

  void ThermistorParamsPanel::updateValues(const shared_ptr<ThermistorModel>& thermistorModel, const std::vector<wxTextCtrl*>& txtCtrls)
  {
    try {
      shared_ptr<Thermistor> thermistor = thermistorModel->generate(this->thermistorTable, *this->leastSquaresSolver.get());
      for (unsigned int i = 0; i < thermistorModel->getNbParameters(); ++i) {
	txtCtrls.at(i)->SetValue(formatValue(thermistor->getParameterValue(i), thermistorModel->getParameterType(i)));
      }
    } catch (std::exception& e) {
      std::cout << "Error updating thermistor parameters for model '" << thermistorModel->getName() <<"': " << e.what() << std::endl;
    }
  }

  void ThermistorParamsPanel::onThermistorTableChanged(ThermistorTable::Event e, ThermistorTableRow* row)
  {
    switch (e) {
    case ThermistorTable::ROW_ADDED:
    case ThermistorTable::ROW_CHANGED:
    case ThermistorTable::ROW_REMOVED:
    case ThermistorTable::BATCH_ENDED:
      updateValues();
      break;
    case ThermistorTable::TABLE_DELETE:
      break;
    }
    
  }

  void ThermistorParamsPanel::addThermistorModelPanel(const shared_ptr<ThermistorModel>& thermistorModel)
  {
    wxSizer* hbox = new wxBoxSizer(wxHORIZONTAL);
   
    wxPanel* panel = new wxPanel(this, wxID_ANY);
    panel->SetSizer(hbox);

    wxSize textCtrlSize(100, wxDefaultSize.GetHeight());
    wxStaticText* stModelName = new wxStaticText(panel, wxID_ANY, wxString::FromUTF8(thermistorModel->getName().c_str()));
    hbox->Add(stModelName, 0, wxALL, 5);
    std::vector<wxTextCtrl*> txtCtrls;
    for (unsigned int i = 0; i < thermistorModel->getNbParameters(); ++i) {
      wxStaticText* stParamName = new wxStaticText(panel, wxID_ANY, wxString::FromUTF8(thermistorModel->getParameterName(i).c_str()));
      wxTextCtrl* txtCtrl = new wxTextCtrl(panel, wxID_ANY, wxString::FromUTF8(""), wxDefaultPosition, textCtrlSize, wxTE_READONLY);
      hbox->Add(stParamName, 0, wxALL, 3);
      hbox->Add(txtCtrl, 0, wxALL, 2);
      txtCtrls.push_back(txtCtrl);
    }
    
    this->thermistorModelMap.insert(std::pair<shared_ptr<ThermistorModel>, std::vector<wxTextCtrl*> >(thermistorModel, txtCtrls));
    GetSizer()->Add(panel);
    updateValues(thermistorModel, txtCtrls);
  }

  wxString ThermistorParamsPanel::formatValue(double v, ThermistorModel::ParameterType type) const
  {
    switch (type) {
    case ThermistorModel::RESISTANCE:
      return wxString::Format(wxT("%.0f"), v);
    case ThermistorModel::TEMPERATURE:
      return wxString::Format(wxT("%.1f"), getTemperatureScale()->fromKelvin(v));
    default:
      return wxString::Format(wxT("%.6g"), v); 
    }
  }

}


